﻿<template>
  <base-dialog
    ref="dialogRef"
    title="修改手机号"
    v-model="innerVisible"
    :close-on-click-modal="false"
    :width="width"
    @cancel="handleCancel"
    @confirm="handleConfirm"
  >
    <!-- 顶部：原手机号 -->
    <div class="origin-mobile" v-if="originMobile">
      原手机号：<span class="num">{{ formatMobile(originMobile) }}</span>
    </div>

    <el-form ref="formRef" :model="form" :rules="rules" class="cm-form">
      <!-- 密码（必填） -->
      <el-form-item prop="password">
        <el-input
          size="large"
          v-model="form.password"
          :type="showPwd ? 'text' : 'password'"
          placeholder="请输入密码"
          show-password
          autocomplete="current-password"
          :name="`pwd_${ts}`"
          @visible-change="showPwd = $event"
        >
          <template #prefix><base-icon :size="14" name="iconfont-general gen-suo" /></template>
        </el-input>
      </el-form-item>

      <!-- 新手机号（必填） -->
      <el-form-item prop="newMobile">
        <el-input
          size="large"
          v-model.trim="form.newMobile"
          placeholder="请输入新手机号"
          autocomplete="off"
          inputmode="numeric"
          :name="`newmobile_${ts}`"
          maxlength="11"
        >
          <template #prefix><base-icon :size="14" name="iconfont-general gen-zhanghao" /></template>
        </el-input>
      </el-form-item>

      <!-- 图形码（必填） + 图片 -->
      <div class="row-2col">
        <el-form-item prop="imgCode" class="grow">
          <el-input
            size="large"
            v-model.trim="form.imgCode"
            placeholder="请输入安全校验码"
            maxlength="4"
            clearable
            autocomplete="off"
            :name="`imgCode_${ts}`"
          >
            <template #prefix><base-icon :size="14" name="iconfont-general gen-yanzhengma" /></template>
          </el-input>
        </el-form-item>

        <el-image class="captcha-img" :src="captchaUrl" fit="fill" @click="refreshCaptcha">
          <template #error>
            <div class="captcha-fallback" @click.stop="refreshCaptcha">点击刷新</div>
          </template>
        </el-image>
      </div>

      <!-- 短信验证码（必填） + 获取按钮（仅做倒计时，其它频控后端控制） -->
      <el-form-item prop="smsCode">
        <el-input
          size="large"
          v-model.trim="form.smsCode"
          placeholder="请输入验证码"
          maxlength="6"
          autocomplete="one-time-code"
          :name="`sms_${ts}`"
        >
          <template #prefix><base-icon :size="14" name="iconfont-general gen-yanzhengma" /></template>
          <template #suffix>
            <el-button text @mousedown.prevent @click="handleSendSms" class="sms-btn">
              {{ sms.countdown > 0 ? `重新获取${sms.countdown}s` : "获取验证码" }}
            </el-button>
          </template>
        </el-input>
      </el-form-item>
    </el-form>
  </base-dialog>
</template>

<script setup>
  import { SMS_TYPE } from "@/utils/const";

  const props = defineProps({
    modelValue: { type: Boolean, default: false }, // v-model
    width: { type: String, default: "404px" },

    originMobile: { type: String, default: "" }, // 原手机号（展示/接口）
    // 可选自定义 API，未传则走默认 Api.login.*
    getCaptchaApi: { type: Function, default: null }, // () => Promise<{ cid, imageBase64 }>
    sendSmsApi: { type: Function, default: null }, // (payload) => Promise
    changeApi: { type: Function, default: null }, // (payload) => Promise
  });

  const emit = defineEmits(["update:modelValue", "success", "cancel"]);

  const innerVisible = computed({
    get: () => props.modelValue,
    set: v => emit("update:modelValue", v),
  });

  const ts = Date.now();
  const formRef = ref();
  const form = reactive({
    password: "",
    newMobile: "",
    imgCode: "",
    smsCode: "",
    cid: "",
  });

  const showPwd = ref(false);

  /* -------- 规则：严格使用指定文案 -------- */
  const MOBILE_RULE = /^1\d{10}$/;
  const rules = {
    password: [{ required: true, message: "请输入密码", trigger: "blur" }],
    newMobile: [
      { required: true, message: "请输入新手机号", trigger: "blur" },
      {
        validator: (_, v, cb) => (MOBILE_RULE.test(String(v || "")) ? cb() : cb(new Error("请输入正确的手机号"))),
        trigger: "blur",
      },
    ],
    imgCode: [{ required: true, message: "请输入安全校验码", trigger: "blur" }],
    smsCode: [
      { required: true, message: "请输入验证码", trigger: "blur" },
      { validator: (_, v, cb) => (/^\d{4,6}$/.test(v || "") ? cb() : cb(new Error("请输入验证码"))), trigger: "blur" },
    ],
  };

  /* -------- 图形码 -------- */
  const captchaUrl = ref("");
  async function defaultGetCaptcha() {
    const res = await Api.login.GetCodeImg();
    const payload = res?.data ?? res;
    const d = payload?.data ?? payload;
    return { cid: d?.cid || "", imageBase64: d?.imageBase64 || "" };
  }
  async function refreshCaptcha() {
    try {
      const api = props.getCaptchaApi || defaultGetCaptcha;
      const { cid, imageBase64 } = await api();
      form.cid = cid;
      captchaUrl.value = imageBase64;
    } catch (e) {
      console.error("[ChangeMobileDialog] refreshCaptcha:", e);
    }
  }

  /* -------- 短信倒计时（仅UI提示） -------- */
  const sms = reactive({ countdown: 0, sending: false, timer: null });
  function startCountdown(sec = 60) {
    sms.countdown = sec;
    clearInterval(sms.timer);
    sms.timer = setInterval(() => {
      sms.countdown--;
      if (sms.countdown <= 0) {
        clearInterval(sms.timer);
        sms.timer = null;
      }
    }, 1000);
  }
  onBeforeUnmount(() => {
    clearInterval(sms.timer);
    sms.timer = null;
  });

  /* -------- 发送短信 -------- */
  async function defaultSendSms(payload) {
    return Api.login.SendModifyMobile(payload);
  }
  async function handleSendSms() {
    // 仅校验手机号 + 图形码是否填写/格式正确
    const ok = await formRef.value
      .validateField(["newMobile", "imgCode"])
      .then(() => true)
      .catch(() => false);
    if (!ok) return;

    try {
      sms.sending = true;
      const api = props.sendSmsApi || defaultSendSms;
      await api({ mobile: form.newMobile, cid: form.cid, code: form.imgCode, type: SMS_TYPE.CHANGE_MOBILE });
      $msg?.success?.("验证码已发送");
      startCountdown(60);
    } catch (e) {
      // 后端统一做频控/校验码校验：报错时提示并刷新图片
      console.error("[ChangeMobileDialog] sendSms:", e);
      $msg?.error?.("请输入正确的安全校验码");
      refreshCaptcha();
    } finally {
      sms.sending = false;
    }
  }

  /* -------- 确认修改 -------- */
  async function defaultChangeApi(payload) {
    return Api.login.ChangePhone(payload);
  }
  async function handleConfirm() {
    const errors = await formRef.value
      .validate()
      .then(() => null)
      .catch(err => err);
    if (errors) {
      const firstKey = Object.keys(errors)[0];
      const firstMsg = errors[firstKey]?.[0]?.message || "请完善表单";
      $msg?.error?.(firstMsg);
      formRef.value.scrollToField?.(firstKey);
      return;
    }

    try {
      const api = props.changeApi || defaultChangeApi;
      await api({
        mobile: form.newMobile,
        password: form.password,
        code: form.smsCode,
      });
      emit("success");
      resetOnClose();
      innerVisible.value = false;
    } catch (e) {
      console.error("[ChangeMobileDialog] change:", e);
      // $msg?.error?.("手机号修改失败，请重新修改");
      refreshCaptcha();
    }
  }

  function handleCancel() {
    resetOnClose();
    emit("cancel");
  }

  /* -------- 打开/关闭 -------- */
  watch(
    () => innerVisible.value,
    v => {
      if (v) {
        refreshCaptcha();
      } else {
        resetOnClose();
      }
    },
    { immediate: true }
  );

  function resetOnClose() {
    formRef.value?.resetFields?.();
    form.password = "";
    form.newMobile = "";
    form.imgCode = "";
    form.smsCode = "";
    form.cid = "";
    captchaUrl.value = "";
    clearInterval(sms.timer);
    sms.timer = null;
    sms.countdown = 0;
  }

  function formatMobile(m) {
    const s = String(m || "");
    return s.length === 11 ? `${s.slice(0, 3)}****${s.slice(7)}` : s;
  }
</script>

<style scoped>
  .origin-mobile {
    margin-bottom: 24px;
    color: #707089;
    font-size: 14px;
  }
  .origin-mobile .num {
    color: #15194d;
    font-weight: 600;
  }

  .cm-form {
    display: flex;
    flex-direction: column;
    gap: 6px;
  }

  .row-2col {
    display: flex;
    gap: 12px;
    align-items: center;
    margin-bottom: 18px;
  }
  .grow {
    flex: 1;
    margin-bottom: 0;
  }

  .captcha-img {
    width: 120px;
    height: 40px;
    cursor: pointer;
    border-radius: 8px;
    overflow: hidden;
  }
  .captcha-fallback {
    width: 120px;
    height: 40px;
    display: flex;
    align-items: center;
    justify-content: center;
    background: #f5f5f5;
    color: #999;
    border-radius: 8px;
  }

  .sms-btn {
    width: 96px;
    color: var(--bd);
    font-size: 14px;
  }
</style>
